/**
 * @file 创编优化工具函数
 * @author  fanxl
 */
import {
    cloneDeep,
    isEmpty,
    remove,
    isArray,
    get,
    set,
    mapKeys,
    reduce,
    flatten,
    isBoolean,
    filter,
    map,
    fromPairs,
    assign,
    toPairs
} from 'lodash-es';
import type {UnionSpecItem, SpecStruct} from '../interface';
import {updateSpecItem} from './spec';

// 创编优化spec改造
export function toComposedSpec(spec: UnionSpecItem[], struct: SpecStruct[]) {
    const composedSpec = cloneDeep(spec);
    const composedSpecName = map(composedSpec, (v) => v.name);
    let composedKeyDict: Record<string, string> = {};

    const walkUpdate = (struct: SpecStruct[]) => {
        if (struct && !isEmpty(struct)) {
            struct.forEach((structElement) => {
                if (structElement.componentType === 'LIST_CONTAINER' && !isEmpty(structElement.children || [])) {
                    const childrenIndexes = [] as string[];
                    const walkCollectChildrenIndexes = (structs: SpecStruct[]) => {
                        structs.forEach((el) => {
                            composedSpecName.includes(el.componentIndex) && childrenIndexes.push(el.componentIndex);
                            if (el.children && el.children.length) {
                                walkCollectChildrenIndexes(el.children);
                            }
                        });
                    };
                    walkCollectChildrenIndexes(structElement.children || []);
                    let specs = filter(composedSpec, (v) => childrenIndexes.includes(v.name));
                    const insertPath = structElement.childrenInsertPath;
                    if (insertPath) {
                        updateSpecItem(insertPath, composedSpec, (specItem) => {
                            specs = map(specs, (v) => {
                                const copySpec = cloneDeep(v);
                                copySpec.dataType = 'OBJECT';
                                delete copySpec.rules;
                                return copySpec;
                            });
                            if (specItem && specItem.dataType === 'LIST' && specItem.items) {
                                const dict = map(specs, (v) => [v.name, insertPath]);
                                composedKeyDict = assign(composedKeyDict, fromPairs(dict));
                                specItem.items.push(...specs);
                            }
                        });
                        remove(composedSpec, (v) => childrenIndexes.includes(v.name));
                    }
                } else if (structElement.children) {
                    walkUpdate(structElement.children);
                }
            });
        }
    };

    walkUpdate(struct);

    return {
        // 生成的字典表
        composedKeyDict,
        // 结构化后的新spec
        composedSpec
    };
}

const safeGetValue = <T>(value: T, key: string, isShallow: boolean = false) => {
    return isShallow ? value[key as keyof T] : get(value, key);
};

// 正向转换Path
export function transPathWithDict(path: string, dict: Record<string, string>) {
    const dictMap = toPairs(dict);
    for (let i = 0; i < dictMap.length; i++) {
        const [originKey, composedKey] = dictMap[i];
        if (originKey === path) {
            return composedKey;
        }
        const reg = new RegExp('^' + originKey + '.\\[(\\d*)\\](.(.*))?$');
        const regTest = reg.exec(path);
        if (regTest) {
            const [, matchIndex, suffix = ''] = regTest;
            return `${composedKey}.[${matchIndex}].${originKey}${suffix}`;
        }
    }
    return path;
}

// 反向转换Path
export function transPathWithDictReverse(path: string, dict: Record<string, string>) {
    const dictMap = toPairs(dict);
    for (let i = 0; i < dictMap.length; i++) {
        const [originKey, composedKey] = dictMap[i];
        const reg = new RegExp('^' + composedKey + '.\\[(\\d*)\\](.' + originKey + '(.*))?$');
        const regTest = reg.exec(path);
        if (regTest) {
            const [, matchIndex, , suffix = ''] = regTest;
            return `${originKey}.[${matchIndex}]${suffix}`;
        }
    }
    return path;
}

// 创编优化根据字典表转换key
export function transDataWithDict<V extends object>(
    values: V,
    dict: Record<string, string>,
    isShallow: boolean = false
) {
    let copyValues = cloneDeep(values);
    if (!copyValues || isEmpty(copyValues)) {
        return copyValues;
    }
    const dictMap = toPairs(dict);
    if (isShallow) {
        copyValues = mapKeys(copyValues, (value, key) => {
            if (dict[key]) {
                return `${key}_${dict[key]}`;
            }
            const newKey = transPathWithDict(key, dict);
            return newKey;
        }) as any;
        copyValues = reduce(
            dictMap,
            (result: V, curr: string[]) => {
                const composedKey = curr[1] as keyof V;
                const key = curr.join('_') as keyof V;
                const val = result[composedKey];
                if (val) {
                    if (isArray(result[key])) {
                        result[composedKey] = flatten([result[composedKey], result[key]]) as any;
                    } else if (isBoolean(result[key])) {
                        result[composedKey] = result[composedKey] || result[key];
                    }
                } else {
                    result[composedKey] = result[key];
                }
                delete result[key];
                return result;
            },
            copyValues
        );
    } else {
        dictMap.forEach(([originKey, composedKey]) => {
            const originValue = safeGetValue(copyValues, originKey, false);
            const composedValue = safeGetValue(copyValues, composedKey, false);
            if (!originValue || !composedValue) {
                return;
            }
            if (!isArray(originValue) || !isArray(composedValue)) {
                throw new Error(`转换数据不是List类型：originKey:${originKey}, composedKey: ${composedKey}`);
            }
            originValue.forEach((v, index) => {
                const key = `${composedKey}.[${index}].${originKey}`;
                set(copyValues, key, v);
            });
            delete copyValues[originKey as keyof V];
        });
    }
    return copyValues;
}

// 创编优化根据字典表反向转换key
export function transDataWithDictReverse<V extends object>(
    values: V,
    dict: Record<string, string>,
    isShallow: boolean = false
) {
    let copyValues = cloneDeep(values);
    if (!copyValues || isEmpty(copyValues)) {
        return copyValues;
    }
    const dictMap = toPairs(dict);
    if (isShallow) {
        copyValues = mapKeys(copyValues, (value, key) => {
            /**
             * 遇到composedKey和originKey相同的不作处理
             * 目前 originKey 的节点一般只会存在list元素长度的判断
             * 但是结构化后不存在这一类问题
             * 所以对于这一类错误不做反结构化变换
             */
            return transPathWithDictReverse(key, dict);
        }) as any;
    } else {
        dictMap.forEach(([originKey, composedKey]) => {
            const composedValue = safeGetValue(copyValues, composedKey, false);
            if (!composedValue) {
                return;
            }
            if (!isArray(composedValue)) {
                throw new Error(`转换数据不是List类型：composedKey: ${composedKey}`);
            }
            composedValue.forEach((v, index) => {
                const val = safeGetValue(v, originKey, false);
                // origin肯定是简单string
                set(copyValues, `${originKey}.[${index}]` as keyof V, val);
                delete v[originKey];
            });
        });
    }
    return copyValues;
}
